package com.gdatacloud.flow.controller;

import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.io.IOUtils;
import org.apache.ibatis.exceptions.PersistenceException;
import org.flowable.bpmn.model.BpmnModel;
import org.flowable.engine.HistoryService;
import org.flowable.engine.ProcessEngine;
import org.flowable.engine.ProcessEngineConfiguration;
import org.flowable.engine.RepositoryService;
import org.flowable.engine.RuntimeService;
import org.flowable.engine.TaskService;
import org.flowable.engine.history.HistoricActivityInstance;
import org.flowable.engine.repository.ProcessDefinition;
import org.flowable.engine.runtime.Execution;
import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.image.ProcessDiagramGenerator;
import org.flowable.task.api.Task;
import org.flowable.task.api.TaskQuery;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import com.gdata.base.facade.R;
import com.gdatacloud.flow.model.DataGrid;
import com.gdatacloud.flow.model.ProcessModel;
import com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException;

import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;

@RestController
@Api("流程控制")
@RequestMapping("/flow")
public class FlowController {

	@Autowired
    private RuntimeService runtimeService;
    @Autowired
    private TaskService taskService;
    @Autowired
    private RepositoryService repositoryService;
    @Autowired
    private ProcessEngine processEngine;
    @Autowired
    HistoryService historyService;
    
    @ApiOperation("上传一个工作流文件")
	@RequestMapping(value = "/uploadworkflow", method = RequestMethod.POST)
	public String fileupload(@RequestParam MultipartFile uploadfile, HttpServletRequest request) {
		try {
			MultipartFile file = uploadfile;
			String filename = file.getOriginalFilename();
			InputStream is = file.getInputStream();
			repositoryService.createDeployment().addInputStream(filename, is).deploy();
		} catch (Exception e) {
			e.printStackTrace();
		}
		return "index";
	}
    @ApiOperation("查询已部署工作流列表")
	@RequestMapping(value = "/getprocesslists", method = RequestMethod.POST)
	public DataGrid<ProcessModel> getlist(@RequestParam("current") int current, @RequestParam("rowCount") int rowCount) {
		int firstrow = (current - 1) * rowCount;
		List<ProcessDefinition> list = repositoryService.createProcessDefinitionQuery().listPage(firstrow, rowCount);
		int total = repositoryService.createProcessDefinitionQuery().list().size();
		List<ProcessModel> mylist = new ArrayList<ProcessModel>();
		for (int i = 0; i < list.size(); i++) {
			ProcessDefinition pd = list.get(i);
			
			ProcessModel p = new ProcessModel();
			p.setDeploymentId(pd.getDeploymentId());
			p.setId(pd.getId());
			p.setKey(pd.getKey());
			p.setName(pd.getName());
			p.setResourceName(pd.getResourceName());
			p.setDiagramresourcename(pd.getDiagramResourceName());
//			repositoryService.deleteDeployment(pd.getDeploymentId(), true);
			mylist.add(p);
		}
		DataGrid<ProcessModel> grid = new DataGrid<ProcessModel>();
		grid.setCurrent(current);
		grid.setRowCount(rowCount);
		grid.setRows(mylist);
		grid.setTotal(total);
		return grid;
	}
    
    @ApiOperation("删除流程部署")
    @DeleteMapping("/pd")
    public R<String> deleteProcessDef(String deploymentId) {
    	try {    		
    		repositoryService.deleteDeployment(deploymentId);
    	} catch (PersistenceException e) {
    		return R.error("操作失败，请检查依赖");
		}
    	return R.ok(null, "删除成功");
    }
    
    @ApiOperation("查看工作流图片")
	@RequestMapping(value = "/showresource", method = RequestMethod.GET)
	public void export(@RequestParam("pdid") String pdid, @RequestParam("resource") String resource,
			HttpServletResponse response) throws Exception {
		ProcessDefinition def = repositoryService.createProcessDefinitionQuery().processDefinitionId(pdid).singleResult();
		InputStream is = repositoryService.getResourceAsStream(def.getDeploymentId(), resource);
		ServletOutputStream output = response.getOutputStream();
		IOUtils.copy(is, output);
	}
    
    /**
     * 查询流程图
     *
     * @param httpServletResponse
     * @param processId
     * @throws Exception
     */
    @ApiOperation("查看流程图")
    @GetMapping(value = "processDiagram")
    public void genProcessDiagram(HttpServletResponse httpServletResponse, String processId) throws Exception {
        // 查询流程实例
        ProcessInstance pi = runtimeService.createProcessInstanceQuery().processInstanceId(processId).singleResult();

        //流程走完的不显示图
        if (pi == null) {
            return;
        }
        // 任务？这里是根据流程实例查询task，然后又根据task获取它所属的流程实例id，那不还是一样的吗
        Task task = taskService.createTaskQuery().processInstanceId(pi.getId()).singleResult();
        //使用流程实例ID，查询正在执行的执行对象表，返回流程实例对象
        String InstanceId = task.getProcessInstanceId();
        List<Execution> executions = runtimeService
                .createExecutionQuery()
                .processInstanceId(InstanceId)
                .list();

        //得到正在执行的Activity的Id
        List<String> activityIds = new ArrayList<>();
        List<String> flows = new ArrayList<>();
        for (Execution exe : executions) {
            List<String> ids = runtimeService.getActiveActivityIds(exe.getId());
            activityIds.addAll(ids);
        }

        //获取流程图
        BpmnModel bpmnModel = repositoryService.getBpmnModel(pi.getProcessDefinitionId());
        ProcessEngineConfiguration engconf = processEngine.getProcessEngineConfiguration();
        ProcessDiagramGenerator diagramGenerator = engconf.getProcessDiagramGenerator();
        InputStream in = diagramGenerator.generateDiagram(bpmnModel, "png", 
        		activityIds, flows, engconf.getActivityFontName(),
        		engconf.getLabelFontName(), engconf.getAnnotationFontName(), engconf.getClassLoader(), 1.0, true);
        OutputStream out = null;
        byte[] buf = new byte[1024];
        int legth = 0;
        try {
            out = httpServletResponse.getOutputStream();
            while ((legth = in.read(buf)) != -1) {
                out.write(buf, 0, legth);
            }
        } finally {
            if (in != null) {
                in.close();
            }
            if (out != null) {
                out.close();
            }
        }
    }
    
    @ApiOperation("启动流程实例")
	@GetMapping("/start")
	public R start() {
		// 这里先保存提交表单，然后启动流程实例；把当前数据的主键id写入 TODO 接收表单进行存储，获取当前流程对应的表单模块
    	
		// 这里可以把列表中要显示的信息放到工作流中
        Map<String, Object> variables = new HashMap<String, Object>();
        variables.put("groups", "z,y,xxxx");
        String bizKey = System.currentTimeMillis() + "";
        
        ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("holidayRequest", bizKey, variables);
		return R.ok("启动成功" + processInstance.getBusinessKey());
	}
	
	@GetMapping("/tasks")
	public R getTasks(String group, String assignee) {
		TaskQuery query = taskService.createTaskQuery();
		if (group != null) {
			query.taskCandidateGroup(group);
		}
		if (assignee != null) {
			query.taskAssignee(assignee);
		}
        List<Task> tasks = query.list();
        List<Map<String, Object>> list = new ArrayList<Map<String,Object>>();
        // 这里根据查询出的任务列表中的formKey，查询实际的数据列表
        tasks.forEach(item -> {
        	Map<String, Object> m = new HashMap<String, Object>();
        	//2  通过任务对象获取流程实例
            ProcessInstance pi = runtimeService.createProcessInstanceQuery()
            		.processInstanceId(item.getProcessInstanceId()).singleResult();
            String businessKey = pi.getBusinessKey();
            m.put("processInstanceId", pi.getProcessInstanceId());
            m.put("businessKey", businessKey);
            m.put("taskName", item.getName());
            m.put("id", item.getId());
            m.put("dueDate", item.getDueDate());
            m.put("processDefinitionId", item.getProcessDefinitionId());
            list.add(m);
        });
		return R.ok(list);
	}
	
	@PutMapping("/taskComplete")
	public R taskComplete(String taskId) {
		Map<String, Object> variables = new HashMap<String, Object>();
        variables.put("employee", "zhangsan");
        variables.put("approved", true);
		taskService.complete(taskId, variables);
		return R.ok("");
	}
	
	@GetMapping("/history")
	public R getHistory(String group) {
        List<HistoricActivityInstance> activities = historyService.createHistoricActivityInstanceQuery()
        		.processInstanceId("holidayRequest:9:cd172f46-1d15-11ec-8b57-309c23f87c29")
        		.finished()
        		.orderByHistoricActivityInstanceEndTime().asc()
        		.list();
        for (HistoricActivityInstance activity : activities) {
			System.out.println(activity.getActivityId() + " 用时 " + activity.getDurationInMillis() + "毫秒");
		}
		return R.ok(activities.toString());
	}
}
